home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
emerald
/
emrldsys.lha
/
Language
/
Compiler
/
doSymbols.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-16
|
15KB
|
595 lines
/*
* @(#)doSymbols.c 1.7 1/20/89
*/
#include "assert.h"
#include "error.h"
#include "scan.h"
#include "nodes.h"
#include "symbols.h"
#include "MyParser.h"
#include "sequence.h"
#include "semantics.h"
#include "map.h"
#include "system.h"
#include "flags.h"
#include "trace.h"
#include "opNames.h"
extern void defineGlobal(), resolveGlobal();
extern NodePtr buildSymbol();
extern Map objectTable;
Boolean opNamesResolved = FALSE;
typedef struct sIDesc {
NodePtr object;
unsigned int nestingDepth :16;
Boolean inMonitor :1;
Boolean inInit :1;
Boolean inBlock :1;
Boolean movesThings :1;
Boolean movesSelf :1;
unsigned int unused :11;
struct sIDesc *next;
} IDesc, *IDescPtr;
extern int nestingDepth;
static IDescPtr stack = NULL;
static void push(p)
NodePtr p;
{
register IDescPtr t;
t = (IDescPtr) calloc(1, sizeof(IDesc));
t->object = p;
t->nestingDepth = nestingDepth;
t->next = stack;
stack = t;
}
static void pop()
{
IDescPtr this;
/* Pop it from the stack. */
this = stack;
this->object->b.oblit.f.doesNotMoveArguments = !this->movesThings;
this->object->b.oblit.f.doesNotMoveSelf = !this->movesSelf;
stack = this->next;
free((char *)this);
}
static DefineASymbol(p, fKind, isAttached, isMove)
register NodePtr p;
ST_Kinds fKind;
Boolean isAttached, isMove;
{
assert(p->tag == P_SYMDEF);
p->b.symdef.symbol = ST_Define(p->b.symdef.ident, fKind, 1);
if (p->b.symdef.symbol == 0) {
fprintf(stdout, "\"%s\", line %d: %s redefined.\n",
currentFileName, p->lineNumber,
Ident_Name(p->b.symdef.ident));
numberOfSemanticErrors++;
} else {
p->b.symdef.symbol->isAttached = isAttached;
p->b.symdef.symbol->isMove = isMove;
}
}
static void DefineAName(p)
NodePtr p;
{
assert(p->tag == P_OPNAME);
}
/*
* This is called during define symbols, so the symbol field of symbols is
* not defined yet. We now compare on the ident field, since these are in
* the same scope.
*/
static NodePtr findWhereValue(sym, type, where)
NodePtr sym, type, *where;
{
register NodePtr p, q, w = *where;
NodePtr resultWW, resultValue;
Boolean foundIt = FALSE;
if (type->tag != P_BUILTINLIT ||
type->b.builtinlit.whichType != KABSTRACTTYPE) return(NN);
Sequence_For(p, w)
assert(p->tag == P_WHEREWIDGIT);
if (foundIt) {
w->b.children[z__z - 1] = p;
} else {
q = p->b.wherewidgit.sym;
if (q->b.symref.ident == sym->b.symref.ident) {
foundIt = TRUE;
resultWW = p;
if (q->tag == P_SYMDEF) {
ErrorMessage(q, "Type parameters must be constrained using *>");
resultValue = NN;
} else {
assert(q->tag == P_SYMREF);
resultValue = resultWW->b.wherewidgit.type;
}
}
}
Sequence_Next
if (foundIt) {
assert(resultWW->tag == P_WHEREWIDGIT);
w->nChildren --;
resultWW->b.wherewidgit.type = NULL;
FreeNode(resultWW);
return(resultValue);
} else {
resultValue = Construct(P_BUILTINLIT, 0);
resultValue->b.builtinlit.whichType = KANY;
return(resultValue);
}
}
static void checkFunction(p)
register NodePtr p;
{
assert(p->tag == P_OPSIG);
if (p->b.opsig.isFunction) {
if (Sequence_Length(p->b.opsig.results) != 1) {
ErrorMessage(p, "Functions must return one result (not %d)",
Sequence_Length(p->b.opsig.results));
}
}
}
static void defineSymbols(p)
NodePtr p;
{
register NodePtr q, r;
NodePtr whereValue;
int doExit = 0;
if (p == NN) {
return;
} else if ((int)p < 0x200) {
/* it is probably an input token */
return;
} else {
switch (p->tag) {
case P_UNAVAILABLEHANDLER:
doExit = 1;
ST_EnterNewScope(p, C_UnavailableHandler);
break;
case P_VARDECL:
DefineASymbol(p->b.vardecl.sym, ST_Var, p->b.vardecl.isAttached, FALSE);
break;
case P_CONSTDECL:
DefineASymbol(p->b.constdecl.sym, ST_Const, p->b.constdecl.isAttached, FALSE);
break;
case P_PARAM:
/* unavailables show up here */
DefineASymbol(p->b.param.sym, ST_Param, p->b.param.isAttached, p->b.param.move);
break;
case P_WHEREWIDGIT:
if ((int)(p->b.wherewidgit.op) == OIDENTITY) {
assert(p->b.wherewidgit.sym->tag == P_SYMDEF);
DefineASymbol(p->b.wherewidgit.sym, ST_Const, FALSE, FALSE);
} else {
/*
* We have not a definition but a constraint one here.
* Just make sure that this is a symbol reference.
*/
assert((int)p->b.wherewidgit.op == OCONFORMSTO);
assert(p->b.wherewidgit.sym->tag == P_SYMREF);
}
break;
case P_ENUMLIT:
NotImplemented(p, "enumeration literals");
break;
case P_UNIONLIT:
NotImplemented(p, "union literals");
break;
case P_RECORDLIT:
NotImplemented(p, "record literals");
break;
case P_IMPORT:
q = p->b.import.syms;
Sequence_For(r, q)
DefineASymbol(r, ST_Const, FALSE, FALSE);
Sequence_Next
break;
case P_ATLIT:
ST_EnterNewScope(p, C_ATLit);
if (p->b.atlit.name != NN)
DefineASymbol(p->b.atlit.name, ST_Const, FALSE, FALSE);
q = p->b.atlit.ops;
/* q is a sequence of operation signatures. */
Sequence_For(r, q)
ST_EnterNewScope(r, C_OpSig);
defineSymbols(r);
checkFunction(r);
ST_ExitScope();
Sequence_Next
ST_ExitScope();
return;
/*break;*/
case P_OPSIG:
DefineAName(p->b.opsig.name);
checkFunction(p);
q = p->b.opsig.params;
/* q is the parameter list. */
Sequence_For(r, q)
assert(r->tag == P_PARAM);
assert(r->b.param.sym != NN);
whereValue =
findWhereValue(r->b.param.sym, r->b.param.type,
&p->b.opsig.where);
if (whereValue != NN) {
/*
* This operation has a parameter that is a type. This means
* that the operation can only be called at compile time.
*/
p->b.opsig.mustBeCompilerExecuted = TRUE;
defineSymbols(whereValue);
}
r->b.param.constraint = whereValue;
DefineASymbol(r->b.param.sym, ST_Param, r->b.param.isAttached, r->b.param.move);
defineSymbols(r->b.param.type);
Sequence_Next
q = p->b.opsig.results;
/* q is the result list. */
Sequence_For(r, q)
assert(r->tag == P_PARAM);
assert(r->b.param.sym != NN);
DefineASymbol(r->b.param.sym, ST_Result, r->b.param.isAttached, r->b.param.move);
defineSymbols(r->b.param.type);
Sequence_Next
defineSymbols(p->b.opsig.where);
return;
/*break;*/
case P_SYMDEF:
break;
/* enter block */
case P_OBLIT:
ST_EnterNewScope(p, C_ObLit);
assert (p->b.oblit.name != NN);
DefineASymbol(p->b.oblit.name, ST_Const, FALSE, FALSE);
Sequence_For(q, p)
defineSymbols(q);
Sequence_Next
ST_ExitScope();
return;
case P_OPDEF:
doExit = 1;
ST_EnterNewScope(p, C_OpDef);
break;
case P_COMP:
doExit = 1;
ST_EnterNewScope(p, C_Comp);
break;
case P_MONITOR:
doExit = 1;
ST_EnterNewScope(p, C_Monitor);
break;
case P_IFCLAUSE:
defineSymbols(p->b.ifclause.exp);
ST_EnterNewScope(p, C_Block);
defineSymbols(p->b.ifclause.stats);
ST_ExitScope();
return;
case P_BLOCK:
case P_ELSECLAUSE:
case P_LOOPSTAT:
case P_FAILUREHANDLER:
doExit = 1;
ST_EnterNewScope(p, C_Block);
break;
}
Sequence_For(r, p)
defineSymbols(r);
Sequence_Next
if (doExit) ST_ExitScope();
}
}
extern int compareSigs();
static int compareDefs(a, b)
NodePtr *a, *b;
{
assert((*a)->tag == P_OPDEF);
assert((*a)->b.opdef.sig->tag == P_OPSIG);
assert((*a)->b.opdef.sig->b.opsig.name->tag == P_OPNAME);
assert((*b)->tag == P_OPDEF);
assert((*b)->b.opdef.sig->tag == P_OPSIG);
assert((*b)->b.opdef.sig->b.opsig.name->tag == P_OPNAME);
return((*a)->b.opdef.sig->b.opsig.name->b.opname.id -
(*b)->b.opdef.sig->b.opsig.name->b.opname.id);
}
#define MAXOPS 500
static void sortConcreteOps(ct)
register NodePtr ct;
{
NodePtr opArray[MAXOPS], ops, p;
register int nextFree = 0, i;
int stage;
OID prevOp, thisOp;
assert(ct->tag == P_OBLIT);
for (stage = 0; stage < 2; stage++) {
if (stage == 0) {
ops = ct->b.oblit.monitor;
if (ops != NULL) {
assert(ops->tag == P_MONITOR);
ops = ops->b.monitor.ops;
}
} else if (stage == 1) {
ops = ct->b.oblit.ops;
}
Sequence_For(p, ops)
assert(p->tag == P_OPDEF);
assert(nextFree < MAXOPS);
opArray[nextFree++] = p;
Sequence_Next
}
TRACE1(atctsort, 2, "QSorting ct named %s", ATName(ct));
qsort((char *)opArray, nextFree, sizeof(NodePtr), compareDefs);
prevOp = 0;
for (i = 0; i < nextFree; i++) {
TRACE2(atctsort, 4, "Operation %s has number %d",
SigName(opArray[i]->b.opdef.sig), i);
opArray[i]->b.opdef.opNumber = i;
thisOp = opArray[i]->b.opdef.sig->b.opsig.name->b.opname.id;
if (prevOp == thisOp) {
ErrorMessage(ct, "Object \"%s\" multiply defines operation \"%s\"",
ST_SymbolName(ct->b.oblit.name->b.symdef.symbol),
ON_Name(prevOp));
}
prevOp = thisOp;
}
}
void sortATOps(p)
NodePtr p;
{
OID prevOp, thisOp;
register int i;
if (Sequence_Length(p->b.atlit.ops) > 1) {
TRACE1(atctsort, 2, "QSorting at named %s", ATName(p));
qsort((char *)&(p->b.atlit.ops->b.children[0]),
Sequence_Length(p->b.atlit.ops),
sizeof(NodePtr),
compareSigs);
prevOp = 0;
for (i = 0; i < Sequence_Length(p->b.atlit.ops); i++) {
TRACE2(atctsort, 4, "Operation %s has number %d",
SigName(p->b.atlit.ops->b.children[i]), i);
thisOp = p->b.atlit.ops->b.children[i]->b.opsig.name->b.opname.id;
if (prevOp == thisOp) {
ErrorMessage(p, "Type \"%s\" multiply defines operation \"%s\"",
ST_SymbolName(p->b.atlit.name->b.symdef.symbol),
ON_Name(prevOp));
}
prevOp = thisOp;
}
}
}
static void propagateImports(st)
Symbol st;
{
Symbol ost;
register IDescPtr idp;
register NodePtr q;
for (idp = stack; idp != NULL; idp = idp->next) {
Sequence_For(q, idp->object->b.oblit.setq)
assert(q->tag == P_SETQ);
if (q->b.setq.inner->b.symdef.symbol == st) {
ost = q->b.setq.outer->b.symref.symbol;
assert(st->isImport);
if (idp->inBlock && !idp->inInit) {
TRACE1(imports, 1, "Symbol %s used outside initially", ST_SymbolName(st));
st->usedOutsideInitially = TRUE;
} else {
TRACE1(imports, 1, "Symbol %s is not used outside initially", ST_SymbolName(st));
}
break;
}
Sequence_Next
st = ost;
}
}
static void checkMovedThing(p)
NodePtr p;
{
Symbol movedThing, stackSymbol;
if (p->tag == P_SYMREF) {
movedThing = p->b.symref.symbol;
stackSymbol = stack->object->b.oblit.name->b.symdef.symbol;
if (stackSymbol == movedThing) {
stack->movesSelf = TRUE;
} else {
stack->movesThings = TRUE;
}
} else {
stack->movesThings = TRUE;
}
}
static void resolveSymbols(p)
register NodePtr p;
{
int doExit = 0, saveInBlock;
register Symbol st;
register NodePtr q, r, lefts;
if ((int)p < 0x200) return;
else {
switch (p->tag) {
case P_INITDEF:
stack->inInit = TRUE;
resolveSymbols(p->b.initdef.body);
stack->inInit = FALSE;
return;
/* enter block */
case P_ATLIT:
ST_EnterOldScope(p);
push(p);
p->b.atlit.name->b.symdef.symbol->isSelf = TRUE;
p->b.atlit.name->b.symdef.symbol->value.value = p;
resolveSymbols(p->b.atlit.name);
q = p->b.atlit.ops;
Sequence_For(r, q)
ST_EnterOldScope(r);
resolveSymbols(r);
ST_ExitScope();
Sequence_Next
ST_ExitScope();
sortATOps(p);
pop();
return;
/*break;*/
case P_SELFLIT:
p->tag = P_SYMREF;
assert(stack != NULL);
q = stack->object->b.oblit.name;
assert(q->tag == P_SYMDEF);
p->b.symref = q->b.symdef;
break;
case P_OBLIT:
ST_EnterOldScope(p);
push(p);
p->b.oblit.name->b.symdef.symbol->isSelf = TRUE;
p->b.oblit.name->b.symdef.symbol->value.value = p;
Sequence_For(q, p)
resolveSymbols(q);
Sequence_Next
ST_ExitScope();
pop();
sortConcreteOps(p);
return;
case P_SIGNALSTAT:
if (!stack->inMonitor) ErrorMessage(p, "Signal statements must be in monitors");
break;
case P_WAITSTAT:
if (!stack->inMonitor) ErrorMessage(p, "Wait statements must be in monitors");
break;
case P_RETURNSTAT:
case P_RETURNANDFAILSTAT:
break;
case P_CHECKPOINTSTAT:
if (!stack->inMonitor) ErrorMessage(p, "Checkpoint statements must be in monitors");
break;
case P_BLOCK:
saveInBlock = stack->inBlock;
stack->inBlock = TRUE;
ST_EnterOldScope(p);
Sequence_For(q, p)
resolveSymbols(q);
Sequence_Next
stack->inBlock = saveInBlock;
ST_ExitScope();
return;
case P_OPDEF:
p->b.opdef.isMonitored = stack->inMonitor;
ST_EnterOldScope(p);
doExit = TRUE;
break;
case P_IFCLAUSE:
resolveSymbols(p->b.ifclause.exp);
ST_EnterOldScope(p);
resolveSymbols(p->b.ifclause.stats);
ST_ExitScope();
return;
case P_UNAVAILABLEHANDLER:
case P_COMP:
case P_ELSECLAUSE:
case P_LOOPSTAT:
case P_FAILUREHANDLER:
ST_EnterOldScope(p);
doExit = TRUE;
break;
case P_MONITOR:
ST_EnterOldScope(p);
stack->inMonitor = TRUE;
resolveSymbols(p->b.monitor.decls);
resolveSymbols(p->b.monitor.ops);
resolveSymbols(p->b.monitor.init);
resolveSymbols(p->b.monitor.recovery);
stack->inMonitor = FALSE;
ST_ExitScope();
return;
case P_ASSIGNSTAT:
lefts = p->b.assignstat.left;
Sequence_For(r, lefts)
if (r->tag != P_SYMREF) {
ErrorMessage(r, "Syntactic sugarings require the ':=' operator");
resolveSymbols(r);
} else {
assert (r->tag == P_SYMREF);
resolveSymbols(r);
st = ST_Fetch(r->b.symref.symbol);
if (st != NULL) {
if (st->itsKind != ST_Var && st->itsKind != ST_Result) {
ErrorMessage(p, "Assignment to non-variable");
} else if (st->nestingDepth < stack->nestingDepth) {
assert(FALSE);
ErrorMessage(p, "Assignment to imported variable");
} else if (st->nestingDepth == stack->nestingDepth && !stack->inInit) {
ErrorMessage(p, "Assignment to non-monitored instance variables can only be made from the initially");
}
}
}
Sequence_Next
resolveSymbols(p->b.assignstat.right);
return;
case P_SYMREF:
p->b.symref.symbol = ST_Lookup(p->b.symref.ident, 2);
if ((st = p->b.symref.symbol) == 0) {
ErrorMessage(p, "\"%s\" undefined", Ident_Name(p->b.symref.ident));
} else {
#ifdef OLDSTUFF
if (st->isImport && stack->inBlock && !stack->inInit)
#else
if (st->isImport && stack->inBlock)
#endif
propagateImports(st);
}
break;
case P_CONSTDECL:
resolveSymbols(p->b.constdecl.type);
resolveSymbols(p->b.constdecl.value);
return;
case P_OPNAME:
p->b.opname.id = ON_Translate(Ident_Name(p->b.opname.ident));
break;
case P_UNFIXSTAT:
resolveSymbols(p->b.unfixstat.exp);
checkMovedThing(p->b.unfixstat.exp);
return;
case P_MOVESTAT:
case P_FIXSTAT:
case P_REFIXSTAT:
resolveSymbols(p->b.movestat.exp);
resolveSymbols(p->b.movestat.loc);
checkMovedThing(p->b.movestat.exp);
return;
}
Sequence_For(q, p)
resolveSymbols(q);
Sequence_Next
if (doExit) ST_ExitScope();
}
}
void initializeSymbols()
{
}
void processSymbols(fNodePtr)
NodePtr fNodePtr;
{
defineSymbols(fNodePtr);
resolveSymbols(fNodePtr);
opNamesResolved = TRUE;
}